//电子邮件puhalskijsemen@gmail.com
//源码网站 开vpn全局模式打开 http://web3incubators.com/
//电报https://t.me/gamecode999
//网页客服 http://web3incubators.com/kefu.html

import { AudioMgr } from "./AudioManager";
import { BundleNames } from "./BundleConfig";
import { GameDataMgr } from "./GameDataManager";
import { LogMgr } from "./LogManager";
import { NodePoolMag } from "./NodePoolMag";
import { PlayerDataMgr } from './PlayerDataManager';
import ResLoader from "./ResLoader";
import { TipMgr } from "./TipsManager";

/**
 * 建议类名：RandomUtils
 */
class RandomUtils {
    private static _onShowCallback: any = null;
    private static _lastShareTime = 0;
    private static _failedShareCount = 0;

    /**
     * 限制一个数值在指定范围内
     * @param min 最小值
     * @param max 最大值
     * @returns 随机数值
     * 建议方法名：limitInRange
     */
    static limitInRange(min: number, max: number): number {
        min = Math.min(min, max);
        const range = Math.max(min, max) - min;
        return min + Math.random() * range;
    }

    /**
     * 限制一个整数在指定范围内
     * @param min 最小值
     * @param max 最大值
     * @returns 随机整数
     * 建议方法名：limitIntegerInRange
     */
    static limitIntegerInRange(min: number, max: number): number {
        return Math.floor(this.limitInRange(min, max + 1));
    }

    /**
     * 获取指定范围内的随机整数
     * @param min 最小值
     * @param max 最大值
     * @returns 随机整数
     * 建议方法名：getRandomInteger
     */
    static getRandomInteger(min: number, max: number): number {
        if (min > max) {
            [min, max] = [max, min];
        }
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    
    /**
     * 限制精灵的最大尺寸
     * @param sprite 精灵节点
     * @param maxSize 最大尺寸
     * 建议方法名：limitSpriteSize
     */
    static limitSpriteSize(spriteNode: cc.Sprite, maxSize: number): void {
        if (spriteNode.spriteFrame) {
            const originalSize = spriteNode.spriteFrame.getOriginalSize();
            let scale = 1;
            if (originalSize.width > maxSize || originalSize.height > maxSize) {
                scale = originalSize.width > originalSize.height ? maxSize / originalSize.width : maxSize / originalSize.height;
                scale = Math.min(scale, 1);
            }
            spriteNode.node.scale = scale;
        } else {
            spriteNode.node.scale = 1;
        }
    }

    /**
     * 判断一个点是否在矩形内
     * @param point 点
     * @param rect 矩形
     * @returns 是否在矩形内
     * 建议方法名：isPointInRect
     */
    static isPointInRect(targetPoint: cc.Vec2, targetRect: cc.Rect): boolean {
        const left = targetRect.x - targetRect.width / 2;
        const right = targetRect.x + targetRect.width / 2;
        const bottom = targetRect.y - targetRect.height / 2;
        const top = targetRect.y + targetRect.height / 2;
        return targetPoint.x > left && targetPoint.x < right && targetPoint.y > bottom && targetPoint.y < top;
    }

    /**
     * 分享功能
     * @param callback 回调函数
     * 建议方法名：share
     */
    static onShare(shareCallback: (success: boolean) => void): void {
        if (window["tt"]) {
            // mg.shareAppMessage({
            //     success: () => {
            //         callback(true);
            //     }
            // });
        } else if (window["wx"]) {
            this.wxShare(shareCallback);
        }
    }

    /**
     * 微信分享功能
     * @param callback 回调函数
     * 建议方法名：wxShare
     */
    static wxShare(shareCallback: (success: boolean) => void): void {
        if (window["wx"]) {
            this._onShowCallback = () => {
                window["wx"].offShow(this._onShowCallback);
                const currentTime = Date.now();
                if (shareCallback) {
                    if (this._failedShareCount < 2) {
                        if (currentTime - this._lastShareTime > 2000) {
                            if (Math.random() < 0.3) {
                                shareCallback(false);
                                TipMgr.showToast("分享失败,请分享至群聊");
                                this._failedShareCount++;
                            } else {
                                TipMgr.showToast("分享成功");
                                shareCallback(true);
                            }
                        } else {
                            this._failedShareCount++;
                            shareCallback(false);
                            TipMgr.showToast("分享失败,请重新分享");
                        }
                    } else {
                        TipMgr.showToast("分享成功");
                        this._failedShareCount = 0;
                        shareCallback(true);
                    }
                }
            }
            window["wx"].onShow(this._onShowCallback);
            this._lastShareTime = Date.now();
            window["wx"].shareAppMessage({
                imageUrlId: "",
                imageUrl: "https://mmocgame.qpic.cn/wechatgame/bSAKPPBBQFUN44PHyDL1mOY72Z1pA2eT0x3QtvGFxdL0ZPob1wej1Dy32ttBtt5y/0",
                title: "你敢来吃我吗"
            });
        }
    }

    /**
     * 替换字符串中的符号
     * @param str 原始字符串
     * @param symbol 要替换的符号
     * @param replacements 替换内容数组
     * @returns 替换后的字符串
     * 建议方法名：replaceStringSymbols
     */
    static replaceStringSymbols(inputStr: string, targetSymbol: string, replacementsArray: string[]): string {
        let resultStr = inputStr;
        for (const replacement of replacementsArray) {
            resultStr = resultStr.replace(targetSymbol, replacement);
        }
        return resultStr;
    }

    /**
     * 显示金币动画
     * @param toPosition 目标位置
     * @param fromPosition 起始位置
     * @param amount 金币数量
     * @param name 名称
     * @param save 是否保存
     * @param onComplete 完成回调
     * 建议方法名：showCoinAnimation
     */
    static async showCoinAnimation(toPosition: cc.Vec2, fromPosition: cc.Vec2, amount: number, name: string, save: boolean = true, onComplete: Function | null = null): Promise<void> {
        let coinNode = NodePoolMag.instance.getNodeFromPool("coin");
        AudioMgr.playSoundEffect("effect/daozhang", false);
        if (!coinNode) {
            const prefab = await ResLoader.loadRes("common", "prefab/CoinIcon", cc.Prefab);
            NodePoolMag.instance.createNodePool("coin", 1, prefab, null);
        }
        this.playCoinAnimation({
            toPosition: toPosition,
            count: 10,
            amount: amount,
            name: name,
            fromPosition: fromPosition,
            save: save,
            onComplete: onComplete
        });
    }

    /**
     * 清理金币
     * 建议方法名：clearCoins
     */
    static async clearCoins(): Promise<void> {
        cc.director.getScene().children.forEach(child => {
            if (child.name === "fei_yinbi") {
                NodePoolMag.instance.recycleNodeToPool("coin", child);
            }
        });
    }

    /**
     * 播放金币动画
     * @param options 动画选项
     * 建议方法名：playCoinAnimation
     */
    static async playCoinAnimation(animationOptions: any): Promise<void> {
        const getRandomOffset = (range: number) => Math.floor(Math.random() * range);
        const defaultOptions = {
            fromPosition: cc.v2(cc.winSize.width / 2, cc.winSize.height / 2),
            toPosition: cc.v2(-320, 600),
            count: 6,
            amount: 0,
            name: "gold",
            save: true,
            onComplete: null
        };

        const finalOptions = Object.assign({}, defaultOptions, animationOptions);

        for (const key in finalOptions) {
            if (finalOptions[key] == undefined) {
                finalOptions[key] = defaultOptions[key];
            }
        }

        if (finalOptions.save) {
            switch (finalOptions.name) {
                case "yinbi":
                    GameDataMgr.addSilverCoin(finalOptions.amount);
                    break;
                case "power":
                    PlayerDataMgr.addPower(finalOptions.amount);
                    break;
                case "jinbi":
                    PlayerDataMgr.addGold(finalOptions.amount);
                    break;
                case "zuanshi":
                    PlayerDataMgr.addDiamond(finalOptions.amount);
                    break;
            }
        }

        const playSingleGold = async (index: number) => {
            let coinNode = NodePoolMag.instance.getNodeFromPool("coin");
            if (!coinNode) return;

            let sprite = coinNode.getChildByName("img").getComponent(cc.Sprite);
            let spriteFrame: cc.SpriteFrame | null = null;

            switch (finalOptions.name) {
                case "yinbi":
                    spriteFrame = await ResLoader.loadRes(BundleNames.Game, "res/yinbi", cc.SpriteFrame);
                    break;
                case "jinbi":
                    spriteFrame = await ResLoader.loadRes(BundleNames.Common, "res/ui/tu/goldIcon", cc.SpriteFrame);
                    break;
                case "zuanshi":
                    spriteFrame = await ResLoader.loadRes(BundleNames.Common, "res/ui/tu/diamondIcon", cc.SpriteFrame);
                    break;
                case "power":
                    spriteFrame = await ResLoader.loadRes(BundleNames.Common, "res/ui/tu/powerIcon", cc.SpriteFrame);
                    break;
            }

            coinNode.name = "fei_yinbi";
            sprite.spriteFrame = spriteFrame;
            coinNode.zIndex = cc.macro.MAX_ZINDEX;
            LogMgr.debug("金币节点：", coinNode, finalOptions.fromPosition);
            coinNode.setPosition(finalOptions.fromPosition);
            cc.director.getScene().addChild(coinNode);

            const offsetX = getRandomOffset(240) - 120;
            const offsetY = getRandomOffset(240) - 120;
            const delay = getRandomOffset(200) / 1000;

            cc.tween(coinNode)
                .delay(delay)
                .by(0.6, { x: offsetX, y: offsetY }, { easing: cc.easing.quadOut })
                .to(1, { x: finalOptions.toPosition.x, y: finalOptions.toPosition.y }, { easing: cc.easing.quartIn })
                .call(() => {
                    if (index !== 0) {
                        NodePoolMag.instance.recycleNodeToPool("coin", coinNode);
                    } else {
                        if (finalOptions.onComplete) {
                            finalOptions.onComplete();
                        }
                        NodePoolMag.instance.recycleNodeToPool("coin", coinNode);
                    }
                })
                .start();
        };

        for (let i = 0; i < finalOptions.count; i++) {
            await playSingleGold(i);
        }
    }

    /**
     * 布局子节点
     * @param parentNode 父节点
     * @param spacing 间距
     * @param updatePosition 是否更新位置
     * @returns 子节点位置数组
     * 建议方法名：layoutChildren
     */
    static layoutChildren(parentNode: cc.Node, spacing: number = 0, updatePosition: boolean = true): cc.Vec2[] {
        const childNodes = parentNode.children;
        const positions: cc.Vec2[] = [];

        if (childNodes.length <= 1) {
            if (childNodes.length === 1) {
                positions.push(cc.Vec2.ZERO);
                if (updatePosition) {
                    childNodes[0].setPosition(0, 0);
                }
            }
            return positions;
        }

        let totalWidth = 0;
        childNodes.forEach(child => totalWidth += child.width);
        totalWidth += (childNodes.length - 1) * spacing;

        let currentPosition = 0;
        for (let i = -1; i < childNodes.length - 1; i++) {
            currentPosition += i === -1 ? -totalWidth / 2 + childNodes[0].width / 2 : childNodes[i].width / 2 + spacing + childNodes[i + 1].width / 2;
            positions.push(cc.v2(currentPosition, 0));
            if (updatePosition) {
                childNodes[i + 1].x = currentPosition;
            }
        }

        return positions;
    }

    /**
     * 发送埋点
     * @param eventName 事件名称
     * @param itemName 项目名称
     * 建议方法名：sendTrackingEvent
     */
    static sendTrackingEvent(eventName: string, itemName: string): void {
        this.sendTrackingDataByItemName(eventName, itemName);
        LogMgr.debug("发送埋点", eventName, itemName);
    }

    /**
     * 通过项目名称发送埋点数据
     * @param eventName 事件名称
     * @param itemName 项目名称
     * 建议方法名：sendTrackingDataByItemName
     */
    static sendTrackingDataByItemName(eventName: string, itemName: string): void {
        let platform: any;
        if (window["tt"]) {
            platform = window["tt"];
        } else if (window["wx"]) {
            platform = window["wx"];
        }

        if (platform && platform.uma) {
            platform.uma.trackEvent(eventName, { itemName });
        }
    }

    /**
     * 加载等级5效果
     * @param level 等级
     * @param parentNode 父节点
     * @param destroyNode 销毁节点
     * @param loadRes 加载资源函数
     * @param onComplete 完成回调
     * @param onComplete2 完成回调2
     * 建议方法名：loadLevel5Effect
     */
    static async loadLevel5Effect(level: number, parentNode: cc.Node, destroyNode: cc.Node, loadRes: Function, onComplete: Function | null = null, onComplete2: Function | null = null): Promise<void> {
        if (parentNode) {
            parentNode.destroyAllChildren();
        }
        loadRes(BundleNames.Common, `item/item_level5_qi_${level}`, cc.Prefab).then((prefab: cc.Prefab) => {
            const node = cc.instantiate(prefab);
            if (parentNode) {
                node.parent = parentNode;
                node.setPosition(0, 0);
            }
            if (onComplete) {
                onComplete(node);
            }
        });

        if (destroyNode) {
            destroyNode.destroyAllChildren();
        }
        loadRes(BundleNames.Common, `item/item_level5_huo_${level}`, cc.Prefab).then((prefab: cc.Prefab) => {
            const node = cc.instantiate(prefab);
            if (destroyNode) {
                node.parent = destroyNode;
                node.setPosition(0, 0);
            }
            if (onComplete2) {
                onComplete2(node);
            }
        });
    }
}

export default RandomUtils;